Podman - Mise en réseau host et conteneur sans racine (rootless)
Je suppose que vous êtes ici parce que vous souhaitez exécuter une application dans un conteneur Podman et y accéder depuis l'hôte.
Par exemple, vous exécutez Podman sur Linux et vous souhaitez pouvoir exécuter un composant dans un conteneur sans racine, tel qu'une base de données, un courtier de messages ou un cache de données, et y accéder depuis votre application.
Vous pouvez le faire avec la publication de ports, mais comment le faire sans avoir à le faire ?
Une solution consiste à choisir judicieusement votre option de mise en réseau. Il existe un mode réseau qui simplifie la mise en réseau de l'hôte. Jetons d'abord un coup d'œil aux modes réseau.
Voici une table des matières rapide pour que vous puissiez passer directement à la partie dont vous avez besoin :
Les modes réseau contrôlent la façon dont votre conteneur interagit avec d'autres systèmes
Pour une mise en réseau simple de conteneur à hôte, connectez votre conteneur au réseau hôte
Utiliser le réseau hôte pour accéder au port du conteneur depuis l'hôte
Sur le réseau hôte , un conteneur peut également accéder aux ports de l'hôte
Ce que vous devez savoir sur Podman, c'est que, comme docker , il dispose de plusieurs modes réseau différents .
Un mode modifie les capacités de mise en réseau du conteneur, comme les autres conteneurs avec lesquels il peut interagir ou s'il peut voir l'hôte.
Podman propose plusieurs modes réseau différents que vous pouvez définir sur un conteneur :
Mode | Ce qu'il fait |
bridge | Crée une pile réseau sur le réseau de pont par défaut |
none | Aucun réseau n'est mis en place |
container:<id> | Utilise le même réseau qu'un autre conteneur avec IDid |
host | Utilise la pile réseau de l'hôte |
network-id | Utilise un réseau défini par l'utilisateur (que vous pouvez créer à l'aide de podman network create ...) |
ns:<path> | Joint un espace de noms réseau trouvé au chemin<path> |
private | Crée un nouvel espace de noms réseau pour le conteneur |
slirp4netns | Crée une pile de réseau utilisateur avec slirp4netns(il s'agit de l'option par défaut pour les conteneurs sans racine.) |
Comme vous pouvez le constater, il existe un éventail d'options époustouflant.
Le mode que j'ai mis en évidence, le hostmode, est la solution la plus simple pour la mise en réseau hôte-conteneur et conteneur-hôte. Nous verrons cela ensuite.
En mode réseau 'hôte', un conteneur partage l' espace de noms réseau de l'hôte ; ce qui signifie qu'il partage la même interface réseau, les mêmes tables de routage, etc., de sorte qu'il peut "voir" les mêmes choses que l'hôte.
Pouvoir partager la même interface réseau et les mêmes tables de routage peut être très utile, car cela signifie que votre conteneur peut voir et accéder aux services comme s'il s'agissait d'un processus normal (non conteneur). Et votre hôte peut voir et accéder aux services exécutés dans des conteneurs.
Attention à la sécurité ! La connexion d'un conteneur au réseau hôte est généralement considérée comme non sécurisée , car votre conteneur peut essentiellement accéder à d'autres ports. Et cela vous expose à un tas de risques (OMG !)
La page de manuel ( man podman-run) convient également :
Remarque : le mode hôte donne au conteneur un accès complet aux services système locaux tels que D-bus et est donc considéré comme non sécurisé ;
Pour cette raison, il est préférable de l'utiliser uniquement dans le développement. Et vous ne devriez certainement pas l'utiliser pour exécuter des conteneurs en production.
Voyons le réseau hôte en action, pour voir comment nous pouvons accéder à un service exécuté dans un conteneur, à partir de l'hôte.
Nous allons utiliser podman runpour exécuter un processus dans un nouveau conteneur sans racine, et ajouter --network=hostpour l'attacher au réseau hôte :
podman run --network=host nginxinc/nginx-unprivileged
Le serveur Web Nginx s'exécute maintenant sur le port 8080, à l'intérieur d'un conteneur.
(L' nginx-unprivilegedimage est une variante de l' nginximage standard, qui est configurée pour exécuter Nginx sur un port non privilégié.)
Si je vais dans mon navigateur Web sur l'hôte et que j'accède à http://localhost:8080 , je verrai la page d'accueil de nginx :
Lorsqu'un conteneur sans racine est connecté au réseau hôte, vous pouvez accéder à ses ports depuis l'extérieur du conteneur
Comment c'est? Je n'ai configuré aucune publication ou redirection de port… ..
Étant donné que le conteneur est connecté au hostréseau, il se lie à un port dans l'espace de noms réseau de l'hôte. C'est une autre façon de dire qu'il se lie à un port sur l'hôte.
Vous n'avez pas besoin de configurer de publication de port supplémentaire, ni de transfert, ni quoi que ce soit de ce genre. Avec le mode réseau hôte , le réseau est partagé entre l'hôte et le conteneur. Les éléments sur localhost dans le conteneur sont accessibles sur localhost à partir de l'hôte.
La tête haute! Puisque nous exécutons un conteneur sans racine , vous devez vous assurer que l'application n'essaie pas de se lier (s'exécuter) sur un port privilégié, comme le port 80 . S'il essaie de se lier à un port privilégié, vous verrez une erreur comme :
bind() à 0.0.0.0:80 a échoué (13 : autorisation refusée)
Vous devrez donc configurer votre application pour qu'elle se lie à un port non privilégié, qui est un numéro de port commençant par 1024 .
Pourquoi est-ce? Parce que vous exécutez en tant qu'utilisateur non privilégié (c'est-à-dire non root).
À partir des pages de manuel pour man 7 ip(il m'a fallu des siècles pour trouver exactement où cela est décrit dans les pages de manuel !):
Les numéros de port inférieurs à 1024 sont appelés ports privilégiés (ou parfois : ports réservés). Seul un processus privilégié (sous Linux : un processus qui a la capacité CAP_NET_BIND_SERVICE dans l'espace de noms utilisateur régissant son espace de noms réseau) peut lier(2) à ces sockets.
Lorsque vous utilisez le mode réseau hôte , vous pouvez également accéder aux ports de l'hôte depuis l'intérieur du conteneur.
(C'est pourquoi il est considéré comme peu sûr.)
Sur mon système d'exploitation hôte, j'exécute le serveur Web Apache sur le port 80. J'utilise curlpour faire une demande au serveur et obtenir une petite page de test idiote que j'ai créée :
$ curl http://localhost:80
Hello, internet friend!
Que se passe-t-il maintenant lorsque j'exécute la même curl http://localhost:80commande, mais dans un conteneur configuré avec le mode réseau hôte ?
$ podman exec -it 8918c8ebbbfd curl http://localhost:80
Hello, internet friend!
J'obtiens le même résultat! Mon conteneur peut atteindre le serveur Web qui s'exécute sur mon hôte, en utilisant simplement localhost.
Ainsi, lorsqu'un conteneur sans racine utilise le mode réseau hôte , il peut également accéder aux ports de l'hôte en utilisant l'adresse localhost .
J'espère que vous avez tiré 🌠 VALUE 🌠 de cet article et qu'il vous a permis de gagner du temps lors de la configuration des ports et de la mise en réseau avec vos conteneurs Podman sans racine.
N'oubliez pas que vous ne devriez pas vraiment l'utiliser en production. Mais c'est un gain de temps pour le développement et vous permet d'exécuter très facilement des logiciels dans des conteneurs sans vous soucier de la publication de ports.